﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Threading;
using EnvDTE;
using tomenglertde.SetupProject.Model;
using tomenglertde.SetupProject.Tools;

namespace tomenglertde.SetupProject.ViewModel
{
    public class SetupProjectViewModel
    {
        private readonly EnvDTE.Solution _solution;
        private readonly ObservableWrappedCollection<NodeEntity, SetupProjectOutput> _projectOutputs;
        private readonly ObservableWrappedCollection<NodeEntity, SetupFile> _files;

        public SetupProjectViewModel(EnvDTE.Solution solution, EnvDTE.Project project)
        {
            _solution = solution;

            Name = project.Name;
            // Name is the <project display name>
            // FullName is <absolute project folder>\<project display name>
            // UniqueName is <relative project folder>\<project file name>
            // => The correct full name is <absolute project folder>\<project file name>
            FullName = Path.Combine(Path.GetDirectoryName(project.FullName), Path.GetFileName(project.UniqueName));

            Root = Parser.Parse(FullName);

            HierarchyNodes = Root.GetChild("Hierarchy").Children;
            Hierarchy = new ObservableWrappedCollection<NodeEntity, SetupHierarchyEntry>(HierarchyNodes, c => new SetupHierarchyEntry(c, this));

            var deployable = Root.GetChild("Deployable");

            FileNodes = deployable.GetChild("File").Children;
            _files = new ObservableWrappedCollection<NodeEntity, SetupFile>(FileNodes, c => new SetupFile(c, this));
            _files.CollectionChanged += SetupItem_CollectionChanged;

            ProjectOutputNodes = deployable.GetChild("ProjectOutput").Children;
            _projectOutputs = new ObservableWrappedCollection<NodeEntity, SetupProjectOutput>(ProjectOutputNodes, c => new SetupProjectOutput(c, this));
            _projectOutputs.CollectionChanged += SetupItem_CollectionChanged;
        }

        public string Name
        {
            get;
            private set;
        }

        public string FullName
        {
            get;
            private set;
        }

        public NodeEntity Root
        {
            get;
            private set;
        }

        public IList<NodeEntity> ProjectOutputNodes
        {
            get;
            private set;
        }

        public IList<NodeEntity> FileNodes
        {
            get;
            private set;
        }

        public IList<NodeEntity> HierarchyNodes
        {
            get;
            private set;
        }

        public IList<SetupFile> Files
        {
            get
            {
                return _files;
            }
        }

        public IList<SetupHierarchyEntry> Hierarchy
        {
            get;
            private set;
        }

        public IList<SetupProjectOutput> ProjectOutputs
        {
            get
            {
                return _projectOutputs;
            }
        }

        public void Save()
        {
            UnloadProject();

            Parser.Save(FullName, Root);
        }

        private void SetupItem_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            BeginSave();

            if ((e.Action != NotifyCollectionChangedAction.Remove) || (e.OldItems == null))
                return;

            var hierarchyItems = e.OldItems.Cast<SetupItem>().SelectMany(item => Hierarchy.Where(h => ((h.Owner == item.Id) || (h.Id == item.Id)))).ToList();

            hierarchyItems.ForEach(h => HierarchyNodes.Remove(h.Node));
        }

        public override string ToString()
        {
            return Name;
        }

        private void UnloadProject()
        {
            try
            {
                const string vsWindowKindSolutionExplorer = "{3AE79031-E1BC-11D0-8F78-00A0C9110057}";

                var dte = _solution.DTE;

                var solutionExplorer = dte.Windows.Item(vsWindowKindSolutionExplorer) as Window;
                solutionExplorer.Activate();

                var solutionHierarchy = solutionExplorer.Object as UIHierarchy;

                var solutionName = _solution.Properties.Item("Name").Value;
                var projectPath = solutionName + @"\" + Name;

                dynamic obj = solutionHierarchy.GetItem(projectPath);
                obj.Select(vsUISelectionType.vsUISelectionTypeSelect);

                dte.ExecuteCommand("Project.UnloadProject");
            }
            catch (COMException)
            {
            }
        }

        private int _saveRequestCounter;

        internal void BeginSave()
        {
            var dispatcher = Dispatcher.CurrentDispatcher;

            _saveRequestCounter++;

            dispatcher.BeginInvoke(new Action(delegate
            {
                if (--_saveRequestCounter == 0)
                {
                    Save();
                }
            }));
        }
    }
}
